﻿<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				xmlns:peg="http://schemas.zxteam.net/2014/zxlang/peg/v1"
				xmlns:msxsl="urn:schemas-microsoft-com:xslt"
				exclude-result-prefixes="msxsl peg">
	<xsl:output method="text" indent="yes" omit-xml-declaration="yes" encoding="utf-8"/>

	<xsl:template match="/">
		<xsl:variable name="annotationNamespace" select="/peg:grammar/@annotationNamespace"/>

		<xsl:text>using System;
using System.Collections.Generic;
using Nemerle.Assertions;
using Nemerle.Utility;
using Nemerle.Peg;

namespace net.zxteam.zxlang.Lexer.ParserGenerator
{
	[ParserInfo(AnnotationNamespace="</xsl:text>
		<xsl:value-of select="$annotationNamespace"/>
		<xsl:text>")]
	public partial class Parser : IParser
	{
</xsl:text>

		<xsl:apply-templates/>

		<xsl:text>

		private _wrapToken(tokenName : string, token : NToken) : net.zxteam.zxlang.Lexer.ASTNode { net.zxteam.zxlang.Lexer.ASTNode(tokenName, ParsingSource.OriginalText, token, GetText(token)); }
		private _wrapNodes(tokenName : string, nodes : List[net.zxteam.zxlang.Lexer.ASTNode]) : net.zxteam.zxlang.Lexer.ASTNode { net.zxteam.zxlang.Lexer.ASTNode(tokenName, ParsingSource.OriginalText, nodes.ToArray()); }

//    private bigChar(token : NToken) : net.zxteam.zxlang.Lexer.ASTNode { _wrapToken(token); }
//    private smallChar(token : NToken) : net.zxteam.zxlang.Lexer.ASTNode { _wrapToken(token); }
//    private digit(token : NToken) : net.zxteam.zxlang.Lexer.ASTNode { _wrapToken(token); }

//    private bigCharBlock(nodes : List[net.zxteam.zxlang.Lexer.ASTNode]) : net.zxteam.zxlang.Lexer.ASTNode { _wrapNodes(nodes); }
//    private smallCharBlock(nodes : List[net.zxteam.zxlang.Lexer.ASTNode]) : net.zxteam.zxlang.Lexer.ASTNode { _wrapNodes(nodes); }
//    private digitBlock(nodes : List[net.zxteam.zxlang.Lexer.ASTNode]) : net.zxteam.zxlang.Lexer.ASTNode { _wrapNodes(nodes); }

//    private ast(nodes : List[net.zxteam.zxlang.Lexer.ASTNode]) : net.zxteam.zxlang.Lexer.ASTNode { _wrapNodes(nodes); }

		public ParseASTNode(text : String) : ASTNode implements net.zxteam.zxlang.Lexer.IParser.Parse
		{
			def (len, astOption) = TryParse(text);
			when (len &lt;= 0) {
				def (pos, ids) = GetMaxRollbackPosAndIds();
				def msg = "Cannot parse. Error at pos: " + pos + ": " + ParsingSource.OriginalText.Substring(pos, 20);
				throw System.Exception(msg);
			}

			astOption;
		}
	}

}
</xsl:text>
	</xsl:template>

	<xsl:template match="peg:startToken">
		<xsl:text>		private ast(</xsl:text>
		<xsl:apply-templates>
			<xsl:with-param name="stage">ARGUMENTS</xsl:with-param>
		</xsl:apply-templates>
		<xsl:text>) : net.zxteam.zxlang.Lexer.ASTNode 
		{
			ASTNode(/*tokenName*/"tokens", /*originalText*/ParsingSource.OriginalText, </xsl:text>
		<xsl:apply-templates>
			<xsl:with-param name="stage">METHOD_BODY</xsl:with-param>
		</xsl:apply-templates>
		<xsl:text>);
		}
</xsl:text>
	</xsl:template>

	<xsl:template match="peg:token[@name]">
		<xsl:text>		private </xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>Token(</xsl:text>
		<xsl:apply-templates>
			<xsl:with-param name="stage">ARGUMENTS</xsl:with-param>
		</xsl:apply-templates>
		<xsl:text>) : net.zxteam.zxlang.Lexer.ASTNode 
		{ 
			ASTNode(/*tokenName*/"</xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>", /*originalText*/ParsingSource.OriginalText, </xsl:text>
		<xsl:apply-templates>
			<xsl:with-param name="stage">METHOD_BODY</xsl:with-param>
		</xsl:apply-templates>
		<xsl:text>); 
		}
</xsl:text>
	</xsl:template>

	<xsl:template match="peg:tokenRef">
		<xsl:param name="stage"/>

		<xsl:variable name="id">
			<xsl:text>tokenRef_</xsl:text>
			<xsl:value-of select="generate-id(.)"/>
		</xsl:variable>

		<xsl:choose>
			<xsl:when test="$stage = 'ARGUMENTS'">
				<xsl:value-of select="$id"/>
				<xsl:text> : </xsl:text>
				<xsl:choose>
					<xsl:when test="local-name(..) = 'choice'">
						<xsl:text>net.zxteam.zxlang.Lexer.ASTNode</xsl:text>
					</xsl:when>
					<xsl:when test="local-name(..) = 'sequence'">
						<xsl:text>net.zxteam.zxlang.Lexer.ASTNode</xsl:text>
					</xsl:when>
					<xsl:when test="local-name(..) = 'cardinal'">
						<xsl:text>List[net.zxteam.zxlang.Lexer.ASTNode]</xsl:text>
					</xsl:when>
					<xsl:otherwise>
						<xsl:message terminate="yes">
							Not implemented render body for '<xsl:value-of select="local-name(..)"/>' in peg:tokenRef
						</xsl:message>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:when>
			<xsl:when test="$stage = 'METHOD_BODY'">
				<xsl:choose>
					<xsl:when test="local-name(..) = 'choice'">
						<xsl:value-of select="$id"/>
					</xsl:when>
					<xsl:when test="local-name(..) = 'sequence'">
						<xsl:value-of select="$id"/>
					</xsl:when>
					<xsl:when test="local-name(..) = 'cardinal'">
						<xsl:value-of select="$id"/>
						<xsl:text>.ToArray()</xsl:text>
					</xsl:when>
					<xsl:otherwise>
						<xsl:message terminate="yes">
							Not implemented render body for '<xsl:value-of select="local-name(..)"/>' in peg:tokenRef
						</xsl:message>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:when>
			<xsl:otherwise>
				<xsl:message terminate="yes">
					Unknown stage '<xsl:value-of select="$stage"/>' in peg:tokenRef
					<xsl:call-template name="genPath"/>
				</xsl:message>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="peg:sequence">
		<xsl:param name="stage"/>

		<xsl:choose>
			<xsl:when test="$stage = 'ARGUMENTS'">
				<xsl:for-each select="peg:tokenRef">
					<xsl:if test="not(position() = 1)">
						<xsl:text>, </xsl:text>
					</xsl:if>
					<xsl:apply-templates select=".">
						<xsl:with-param name="stage" select="$stage"/>
					</xsl:apply-templates>
				</xsl:for-each>
			</xsl:when>
			<xsl:when test="$stage = 'METHOD_BODY'">
				<xsl:for-each select="peg:tokenRef">
					<xsl:if test="not(position() = 1)">
						<xsl:text>, </xsl:text>
					</xsl:if>
					<xsl:apply-templates select=".">
						<xsl:with-param name="stage" select="$stage"/>
					</xsl:apply-templates>
				</xsl:for-each>
			</xsl:when>
			<xsl:otherwise>
				<xsl:message terminate="yes">
					Unknown stage '<xsl:value-of select="$stage"/>' in peg:sequence.
					<xsl:call-template name="genPath"/>
				</xsl:message>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="peg:choice">
		<xsl:param name="stage"/>

		<xsl:choose>
			<xsl:when test="$stage = 'ARGUMENTS'">
				<xsl:apply-templates select="./*[1]">
					<xsl:with-param name="stage" select="$stage"/>
				</xsl:apply-templates>
			</xsl:when>
			<xsl:when test="$stage = 'METHOD_BODY'">
				<xsl:apply-templates select="./*[1]">
					<xsl:with-param name="stage" select="$stage"/>
				</xsl:apply-templates>
			</xsl:when>
			<xsl:otherwise>
				<xsl:message terminate="yes">
					Unknown stage '<xsl:value-of select="$stage"/>' in peg:sequence.
					<xsl:call-template name="genPath"/>
				</xsl:message>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="peg:cardinal">
		<xsl:param name="stage"/>

		<xsl:choose>
			<xsl:when test="$stage = 'ARGUMENTS'">
				<xsl:apply-templates select="./*[1]">
					<xsl:with-param name="stage" select="$stage"/>
				</xsl:apply-templates>
			</xsl:when>
			<xsl:when test="$stage = 'METHOD_BODY'">
				<xsl:apply-templates select="./*[1]">
					<xsl:with-param name="stage" select="$stage"/>
				</xsl:apply-templates>
			</xsl:when>
			<xsl:otherwise>
				<xsl:message terminate="yes">
					Unknown stage '<xsl:value-of select="$stage"/>' in peg:sequence.
					<xsl:call-template name="genPath"/>
				</xsl:message>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="peg:range | peg:text">
		<xsl:param name="stage"/>

		<xsl:variable name="id">
			<xsl:text>tokenRef_</xsl:text>
			<xsl:value-of select="generate-id(.)"/>
		</xsl:variable>

		<xsl:choose>
			<xsl:when test="$stage = 'ARGUMENTS'">
				<xsl:value-of select="$id"/>
				<xsl:text> : NToken</xsl:text>
			</xsl:when>
			<xsl:when test="$stage = 'METHOD_BODY'">
				<xsl:value-of select="$id"/>
				<xsl:text>, GetText(</xsl:text>
				<xsl:value-of select="$id"/>
				<xsl:text>)</xsl:text>
			</xsl:when>
			<xsl:otherwise>
				<xsl:message terminate="yes">
					Unknown stage '<xsl:value-of select="$stage"/>' in peg:range
				</xsl:message>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="text()"/>


	<xsl:template name="genPath">
		<xsl:param name="prevPath"/>
		<xsl:variable name="currPath" select="concat('/',name(),'[',
      count(preceding-sibling::*[name() = name(current())])+1,']',$prevPath)"/>
		<xsl:for-each select="parent::*">
			<xsl:call-template name="genPath">
				<xsl:with-param name="prevPath" select="$currPath"/>
			</xsl:call-template>
		</xsl:for-each>
		<xsl:if test="not(parent::*)">
			<xsl:value-of select="$currPath"/>
		</xsl:if>
	</xsl:template>

</xsl:stylesheet>
